#define MAX_COMP(vec) (max(vec.x, max(vec.y, vec.z)))

float perlin(float3 p) {
	float3 i = floor(p);
	float4 a = dot(i, float3(1., 57., 21.)) + float4(0., 57., 21., 78.);
	float3 f = cos((p-i)*acos(-1.))*(-.5)+.5;
	a = lerp(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
	a.xy = lerp(a.xz, a.yw, f.y);
	return lerp(a.x, a.y, f.z);
}

float fractalsum(float3 Q)
{
	const float MINFREQ = 2.0f;
	const float MAXFREQ = 32.0f;
	float value = 0;
	for (float f = MINFREQ; f < MAXFREQ; f *= 2)
		value += abs(perlin(Q * f)/f);
	return value;
}

float distanceSphere(float3 p, float r)
{
	return length(p) - r;
}

/*
float distanceBox(float3 p, float3 boxMin, float3 boxMax)
{
	float3 closestPointOnBox;
	closestPointOnBox.x = (p.x < boxMin.x) ? boxMin.x : (p.x > boxMax.x) ? boxMax.x : p.x;
	closestPointOnBox.y = (p.y < boxMin.y) ? boxMin.y : (p.y > boxMax.y) ? boxMax.y : p.y;
	closestPointOnBox.z = (p.z < boxMin.z) ? boxMin.z : (p.z > boxMax.z) ? boxMax.z : p.z;
	return distance(p, closestPointOnBox);
}
*/

float distanceBox(float3 p, float3 b)
{
	const float3 di = abs(p) - b;
    const float mc = MAX_COMP(di);
    return mc < 0.0f ? mc : length(max(di,0.0f));
}

float distanceRouBox(float3 p, float4 b)
{
	float rad = b.w;
    return length( max( abs(p) - b.xyz + float3(rad, rad, rad), 0.0 ) ) - rad;
}

float distanceTorus(float3 p, float2 t) // t.x - R, t.y - r
{
	return length(float2(length(p.xy) - t.x, p.z)) - t.y;
}

float distancePlane(float3 p)
{
	return dot(p, float3(0.0f, 1.0f, 0.0f));
}

#define Rotate(p,a) p=float2(p.x*cos(a)+p.y*sin(a),p.y*cos(a)-p.x*sin(a))

float3 rotateY(float3 p, float angle)
{
	float cosa = cos(angle);
	float sina = sin(angle);
	float2x2 rot;
	rot[0][0] = cosa;
	rot[0][1] = -sina;
	rot[1][0] = sina;
	rot[1][1] = cosa;
	p.xz = mul(p.xz, rot);
	return p;
}

/*
float raySphereIntersect(float3 rayPos, float3 rayDir, float4 sphere)
{
	float t = NO_INTERSECTION;
	
	float3 dist = rayPos - sphere.xyz;
	float B = dot(dist, rayDir);
	float C = dot(dist, dist) - sphere.w * sphere.w;
	float delta = B*B - C;
	if(delta > 0.0f)
	{
		t = - B - sqrt(delta);
	}	
	return t;
}
*/
